package com.tianxiabuyi.utils;


import com.tianxiabuyi.Input;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

import javax.servlet.jsp.JspWriter;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by yang on 2017/3/27.
 */
public final class Tools {
    /**
     * 获取object,如果null则返回defaultObject
     */
    public static <T> T getObject(T object, T defaultObject) {
        if (null == object) {
            return defaultObject;
        }
        return object;
    }

    /**
     * 通过Object类型获取String,如果null则返回暂无
     */
    public static String getDesc(Object value) {
        return getDesc(value, StringUtil.DEFAULT_VALUE);
    }

    /**
     * 通过Object类型获取String,如果为null则返回defaultShow
     * @param value 要获取的Object类型
     * @param defaultShow 如果value为null时返回defaultShow
     */
    public static String getDesc(Object value, String defaultShow) {
        return getDesc(value + "", defaultShow, 0);
    }

    /**
     * 通过String类型获取String,如果为null则返回defaultShow,不为null则返回max长度字符串
     */
    public static String getDesc(String value, Integer beginIndex) {

        return getDesc(value, StringUtil.DEFAULT_VALUE, beginIndex);
    }

    public static String getDesc(String value, String defaultShow, Integer beginIndex) {
        if ((value + "").equals("null")) {
            return defaultShow;
        }
        value = value.trim();
        return getDesc(value, defaultShow, beginIndex, value.length());
    }

    public static String getDesc(String value, Integer beginIndex, Integer endIndex) {
        return getDesc(value, StringUtil.DEFAULT_VALUE, beginIndex, endIndex);
    }

    public static String getDesc(String value, String defaultShow, Integer beginIndex, Integer endIndex) {
        if ((value + "").equals("null")) {
            return defaultShow;
        }

        value = value.substring(beginIndex, endIndex);
        return value;
    }

    public static Long getLong(String value, Long defaultLong) {
        Long v = getLong(value);
        if (v == null) {
            return defaultLong;
        }
        return v;
    }

    public static Long getLong(String value) {
        if (value == null) {
            return null;
        }
        try {
            return Long.parseLong(value.trim());
        } catch (Exception ex) {
            return null;
        }
    }

    public static Double getDouble(String value, Double defaultDouble) {
        Double v = getDouble(value);
        if (v == null) {
            return defaultDouble;
        }
        return v;
    }

    public static Double getDouble(String value) {
        if (value == null) {
            return null;
        }
        try {

            return Double.parseDouble(value.trim());
        } catch (Exception ex) {
            return null;
        }
    }

    public static Float getFloat(String value, Float defaultFloat) {
        Float v = getFloat(value);
        if (v == null) {
            return defaultFloat;
        }
        return v;
    }

    public static Float getFloat(String value) {
        if (value == null) {
            return null;
        }
        try {
            return Float.parseFloat(value.trim());
        } catch (Exception ex) {
            return null;
        }
    }

    public static Integer getInt(int value) {
        return getInt(value + "");
    }

    public static Integer getInt(int value, Integer defaultValue) {
        return getInt(value + "", defaultValue);
    }

    public static Integer getInt(String value, Integer defaultInteger) {
        Integer v = getInt(value);
        if (v == null) {
            return defaultInteger;
        }
        return v;
    }

    public static Integer getInt(String value) {
        try {
            return Integer.parseInt(value.trim());
        } catch (Exception ex) {
            return null;
        }
    }

    public static Boolean getBool(String value) {
        if (value == null) {
            return null;
        }
        try {
            return Boolean.parseBoolean(value);
        } catch (Exception ex) {
            return null;
        }
    }

    public static String getMD5(String source) {
        return getMD5(source, null);
    }

    public static String getMD5(String source, String encode) {
        String s = null;
        char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                'a', 'b', 'c', 'd', 'e', 'f' };
        try {
            java.security.MessageDigest md = java.security.MessageDigest
                    .getInstance("MD5");
            if (encode == null) {
                md.update(source.getBytes());
            } else {
                md.update(source.getBytes(encode));
            }
            byte tmp[] = md.digest(); // MD5 的计算结果是一个 128 位的长整数，
            // 用字节表示就是 16 个字节
            char str[] = new char[16 * 2]; // 每个字节用 16 进制表示的话，使用两个字符，
            // 所以表示成 16 进制需要 32 个字符
            int k = 0; // 表示转换结果中对应的字符位置
            for (int i = 0; i < 16; i++) { // 从第一个字节开始，对 MD5 的每一个字节
                // 转换成 16 进制字符的转换
                byte byte0 = tmp[i]; // 取第 i 个字节
                str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字节中高 4 位的数字转换,
                // >>> 为逻辑右移，将符号位一起右移
                str[k++] = hexDigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换
            }
            s = new String(str); // 换后的结果转换为字符串

        } catch (Exception e) {
            e.printStackTrace();
        }
        return s;
    }

    /**
     * 使用Crypt中默认的密钥加密
     * @param src 要加密的字符串
     */
    public static String encryptStr(String src) {
        return Crypt.encryptStr(src);
    }

    /**
     * 使用指定的密钥加密
     * @param src 要加密的字符串
     * @param key 密钥
     */
    public static String encryptStr(String src, String key) {
        return Crypt.encryptStr(src, key);
    }

    /**
     * 使用Crypt中默认的密钥解密
     * @param src 要解密的字符串
     */
    public static String decryptStr(String src) {
        return Crypt.decryptStr(src);
    }

    /**
     * 使用指定的密钥解密
     * @param src 要解密的字符串
     * @param key 密钥
     */
    public static String decryptStr(String src, String key) {
        return Crypt.decryptStr(src, key);
    }

    /**
     * 输出字符串到客户端
     * @param out Servlet中的out对象
     * @param str 要输出的字符串
     * @param crypt 是否加密
     * @throws Exception
     */
    private static void print(JspWriter out, String str, boolean crypt)
            throws Exception {
        if (null == str)
            throw new NullPointerException("str");
        out.clear();
        str = str.trim();
        out.print(str = crypt ? encryptStr(str) : str);
    }

    /**
     * 输出字符串到客户端
     */
    public static void print(JspWriter out, String str) throws Exception {
        print(out, str, false);
    }

    /**
     * 输出字符串到客户端
     */
    public static void print(JspWriter out, Object obj) throws Exception {
        print(out, obj.toString(), false);
    }

    /**
     * 加密输出字符串到客户端
     */
    public static void encryptPrint(JspWriter out, String str) throws Exception {
        print(out, str, true);
    }

    /**
     * 加密输出字符串到客户端
     */
    public static void encryptPrint(JspWriter out, Object obj) throws Exception {
        print(out, obj.toString(), true);
    }

    /**
     * 获得对象的所有成员变量
     * @param classTye 对象类型
     * @return 成员变量list
     */
    public static List<Field> getDeclaredFields(Class<?> classTye) {
        // 子类成员变量
        Field[] subFiled = classTye.getDeclaredFields();
        // 父类成员变量
        Field[] superField = classTye.getSuperclass().getDeclaredFields();
        // 合并后的成员变量
        List<Object> list = Tools.combineArrays(subFiled, superField);
        List<Field> fields = new ArrayList<Field>();
        for (int i = 0; i < list.size(); i++) {
            fields.add((Field) list.get(i));
        }
        return fields;
    }

    /**
     * 对象转map
     * @param object Object类型对象
     * @return map
     */
    public static Map<String, Object> toMap(Object object) {
        HashMap<String, Object> map = new HashMap<String, Object>();
        if (object == null) {
            return map;
        }

        try {
            // 对象类型
            Class<?> classTye = object.getClass();
            // 获得对象的所有成员变量
            List<Field> list = Tools.getDeclaredFields(classTye);
            for (int i = 0; i < list.size(); i++) {
                Field field = (Field) list.get(i);
                String fieldName = field.getName();
                field.setAccessible(true);
                Object o = field.get(object);
                if (o != null) {
                    map.put(fieldName, o);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return map;
    }

    /**
     * 一个或多个数组合并后添加到list中
     * @param objects Object类型的可变数组参数
     * @return 合并后的list
     */
    public static List<Object> combineArrays(Object[]... objects) {
        List<Object> list = new ArrayList<Object>();
        for (int i = 0; i < objects.length; i++) {
            list.addAll(Arrays.asList(objects[i]));
        }
        return list;
    }

    /**
     * 生成url请求参数
     */
    public static String genUrlParams(Input input) {
        return genUrlParams(input.getParameters());
    }

    /**
     * 生成url请求参数
     */
    public static String genUrlParams(Map<String, String> map) {
        Object[] keys = map.keySet().toArray();
        String params = "";
        for (int i = 0; i < keys.length; i++) {
            try {
                if (map.get(keys[i]) != null) {
                    String value = URLEncoder.encode(map.get(keys[i]) + "", "utf-8");
                    params = params + "&" + keys[i] + "=" + value;
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        if (params.length() > 0) {
            params = params.substring(1, params.length());
        }
        return params;
    }

    /**
     * 将汉字转换为全拼
     * @param src
     * @return
     */
    public static String getPinYin(String src) {
        char[] ch = null;
        ch = src.toCharArray();
        String[] str = new String[ch.length];
        HanyuPinyinOutputFormat output = new HanyuPinyinOutputFormat();
        output.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        output.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        output.setVCharType(HanyuPinyinVCharType.WITH_V);
        String pinYin = "";
        int len = ch.length;
        try {
            for (int i = 0; i < len; i++) {
                // 判断是否为汉字字符
                if (java.lang.Character.toString(ch[i]).matches("[\\u4E00-\\u9FA5]+")) {
                    str = PinyinHelper.toHanyuPinyinStringArray(ch[i], output);
                    pinYin += str[0];
                } else
                    pinYin += java.lang.Character.toString(ch[i]);
            }
            return pinYin;
        } catch (BadHanyuPinyinOutputFormatCombination e1) {
            e1.printStackTrace();
        }
        return pinYin;
    }

    /**
     * 返回中文的首字母
     * @param str
     * @return
     */
    public static String getPinYinHeadChar(String str) {
        String convert = "";
        for (int j = 0; j < str.length(); j++) {
            char word = str.charAt(j);
            String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);
            if (pinyinArray != null) {
                convert += pinyinArray[0].charAt(0);
            } else {
                convert += word;
            }
        }
        return convert;
    }


    /**
     * 判断对象是否为空
     * @param o
     * @return
     */
    public static boolean isEmpty(Object o) {
        if (o == null) {
            return true;
        }
        String type = o.getClass().getName();
        if ("java.lang.String".equals(type)) {
            String result = (String)o;
            return result.trim().length() == 0;
        } else if (type.startsWith("java.util.") && type.endsWith("List")) {
            List result = (List)o;
            return result.size() == 0;
        } else if (type.startsWith("java.util.") && type.endsWith("Map")) {
            Map result = (Map)o;
            return result.size() == 0;
        } else if (type.startsWith("[")) {
            return Array.getLength(o) == 0;
        }
        return false;
    }

    /**
     * 匹配是否包含数字
     * @param str 可能为中文，也可能是-19162431.1254，不使用BigDecimal的话，变成-1.91624311254E7
     * @return
     * @author mafh
     * @date 2017/06/14 10:20
     */
    public static boolean isNumeric(String str){
        // 该正则表达式可以匹配所有的数字 包括负数
        Pattern pattern = Pattern.compile("-?[0-9]+\\.?[0-9]*");
        String bigStr;
        try {
            bigStr = new BigDecimal(str).toString();
        }catch (Exception e){
            return false;//异常 说明包含非数字。
        }
        Matcher isNum = pattern.matcher(bigStr);// matcher是全匹配
        if(!isNum.matches()){
            return false;
        }
        return true;
    }

}